/**
 * Electron主进程 - TypeScript版本
 * 负责应用的生命周期管理、窗口创建和IPC通信处理
 */

// 导入所需模块
import * as path from 'path'
import { app, BrowserWindow, ipcMain } from 'electron'
import { electronApp, is } from '@electron-toolkit/utils'
// electron-store 11.x 版本导入
import Store from 'electron-store'
import * as os from 'os'
import * as remoteMain from '@electron/remote/main/index.js'
import * as fs from 'fs'
// SQLite数据库
import Database from 'better-sqlite3'

// 直接在主进程中实现数据格式化函数，避免导入兼容性问题
const dataFormat = (data: any) => {
  try {
    // 简单的JSON序列化，Electron主进程中不需要Vue的toRaw
    return JSON.stringify(data, null, 2)
  } catch (error) {
    console.error('数据格式化失败:', error)
    return String(data)
  }
}

// 连接状态类型
type ConnectionStatus =
  | '未连接'
  | '连接中'
  | '已连接'
  | '已断开'
  | '连接失败'
  | '连接错误'

// 处理__dirname路径
// 在开发环境中使用标准的__dirname
// 在生产环境中，当应用被打包为asar文件时，我们需要正确解析路径
const __dirname = app.isPackaged
  ? path.dirname(app.getAppPath())
  : process.cwd()
console.log('__dirname:', __dirname)

// 启用remote模块
remoteMain.initialize()

// 自定义存储配置
const store = new Store({
  // 存储文件名称
  name: 'data',
  // 扩展名
  extension: 'json',
  // 默认值
  defaults: {
    user: {}
  },
  // 自定义目录
  cwd: path.join(os.homedir(), '.chat')
})

// 窗口对象
const windows: {
  main?: BrowserWindow
  login?: BrowserWindow
  adduser?: BrowserWindow
  friendrequest?: BrowserWindow
} = {}

// SQLite数据库实例
let db: any = null

// 引入WebSocket类型和实现
// 存储WebSocket状态
let wsStatus: ConnectionStatus = '未连接'
// 存储WebSocket实例
let ws: WebSocket | null = null
// 存储消息发送队列，当WebSocket不可用时暂存消息
const messageQueue: any[] = []
// 标记是否有可用的WebSocket
let wsAvailable: boolean = false
// WebSocket服务器URL
let wsUrl: string = ''
// 用户ID
let currentUserId: string = ''
// 心跳计时器ID
let heartbeatTimer: number | null = null
// 重连尝试次数
let reconnectAttempts = 0
// 是否手动关闭连接
let isManualClose = false
// 默认重连时间
const defaultReconnectInterval = 5000
// 上次初始化时间，用于防抖
let lastInitTime = 0

/**
 * 初始化SQLite数据库
 * 在Electron主进程中安全地创建和管理数据库连接
 */
function initializeDatabase() {
  try {
    // 数据库文件路径
    const dbDir = path.join(app.getPath('userData'), 'data')

    // 确保目录存在
    if (!fs.existsSync(dbDir)) {
      fs.mkdirSync(dbDir, { recursive: true })
    }

    const dbPath = path.join(dbDir, 'messages.db')
    console.log('初始化SQLite数据库，路径:', dbPath)

    // 创建数据库连接
    db = new Database(dbPath, {
      verbose: process.env.NODE_ENV === 'development' ? console.log : undefined
    })

    // 启用外键约束和WAL模式提高性能
    if (db) {
      db.pragma('foreign_keys = ON')
      db.pragma('journal_mode = WAL')
    }

    // 初始化表结构
    initTables()

    console.log('SQLite数据库初始化成功')
  } catch (error) {
    console.error('初始化数据库失败:', error)
    db = null
  }
}

/**
 * 初始化数据库表结构
 */
function initTables() {
  try {
    if (!db) {
      throw new Error('数据库连接未建立')
    }

    // 创建消息表和好友申请表
    db.exec(`
      CREATE TABLE IF NOT EXISTS messages (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        local_id TEXT NOT NULL UNIQUE,
        content TEXT NOT NULL,
        type TEXT DEFAULT 'text',
        status INTEGER NOT NULL CHECK(status IN (0, 1, 2)),
        timestamp TEXT DEFAULT (datetime('now', 'localtime')),
        conversation_id TEXT NOT NULL,
        sender_id TEXT
      );
      
      -- 创建好友申请表
      CREATE TABLE IF NOT EXISTS friend_request (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        fromUserId TEXT NOT NULL,
        toUserId TEXT NOT NULL,
        status TEXT DEFAULT 'pending',
        fromUserNickname TEXT NOT NULL,
        toUserNickname TEXT NOT NULL,
        fromUserAvatar TEXT NOT NULL,
        toUserAvatar TEXT NOT NULL,
        note TEXT,
        createTime TEXT DEFAULT (datetime('now', 'localtime'))
      );
      
      -- 创建索引提高查询性能
      CREATE INDEX IF NOT EXISTS idx_messages_conversation_id ON messages(conversation_id);
      CREATE INDEX IF NOT EXISTS idx_messages_local_id ON messages(local_id);
      CREATE INDEX IF NOT EXISTS idx_messages_status ON messages(status);
      
      -- 为好友申请表创建索引
      CREATE INDEX IF NOT EXISTS idx_friend_request_from_user ON friend_request(fromUserId);
      CREATE INDEX IF NOT EXISTS idx_friend_request_to_user ON friend_request(toUserId);
      CREATE INDEX IF NOT EXISTS idx_friend_request_status ON friend_request(status);
    `)

    console.log('数据库表结构初始化成功')
  } catch (error) {
    console.error('初始化数据库表结构失败:', error)
    throw error
  }
}

/**
 * 添加新消息到数据库
 * @param message 消息对象
 * @returns 包含插入ID的操作结果
 */
function addMessageToDatabase(message: any) {
  try {
    if (!db) {
      throw new Error('数据库连接未建立')
    }

    const insertStmt = db.prepare(`
      INSERT INTO messages 
      (local_id, content, type, status, timestamp, conversation_id, sender_id)
      VALUES (@local_id, @content, @type, @status, @timestamp, @conversation_id, @sender_id)
    `)

    const result = insertStmt.run({
      ...message,
      timestamp: message.timestamp || new Date().toLocaleString(), // 生成ISO格式时间戳,
      type: message.type || 'text'
    })

    console.log('消息添加成功:', result)
    return { lastInsertRowid: result.lastInsertRowid }
  } catch (error) {
    console.error('添加消息失败:', error)
    throw error
  }
}

/**
 * 更新消息状态
 * @param local_id 本地消息ID
 * @param status 新的消息状态
 * @returns 包含影响行数的操作结果
 */
function updateMessageStatusInDatabase(local_id: string, status: number) {
  try {
    if (!db) {
      throw new Error('数据库连接未建立')
    }

    const updateStmt = db.prepare(`
      UPDATE messages SET status = @status WHERE local_id = @local_id
    `)

    const result = updateStmt.run({ local_id, status })

    console.log('消息状态更新成功:', result)
    return { changes: result.changes }
  } catch (error) {
    console.error('更新消息状态失败:', error)
    throw error
  }
}

/**
 * 添加好友请求到数据库
 * @param request 好友请求对象
 * @returns 包含插入ID的操作结果
 */
function addFriendRequest(request: {
  id?: number
  fromUserId: string
  toUserId: string
  status?: string
  note?: string
  fromUserNickname: string
  toUserNickname: string
  fromUserAvatar: string
  toUserAvatar: string
  createTime?: string
}) {
  try {
    if (!db) {
      throw new Error('数据库连接未建立')
    }

    const insertStmt = db.prepare(`
      INSERT INTO friend_request 
      (id, fromUserId, toUserId, status, note, fromUserNickname, toUserNickname, fromUserAvatar, toUserAvatar, createTime)
      VALUES (@id, @fromUserId, @toUserId, @status, @note, @fromUserNickname, @toUserNickname, @fromUserAvatar, @toUserAvatar, @createTime)
    `)

    const result = insertStmt.run({
      ...request
    })
    console.log('好友请求添加成功:', result)
    return { lastInsertRowid: result.lastInsertRowid }
  } catch (error) {
    console.error('添加好友请求失败:', error)
    throw error
  }
}

/**
 * 更新好友请求状态
 * @param id 请求ID
 * @param status 新的状态（pending/accepted/rejected）
 * @returns 包含影响行数的操作结果
 */
function updateFriendRequestStatus(id: number, status: string) {
  try {
    if (!db) {
      throw new Error('数据库连接未建立')
    }
    const updateStmt = db.prepare(`
      UPDATE friend_request SET status = @status WHERE id = @id
    `)
    const result = updateStmt.run({ id, status })
    console.log('好友请求状态更新成功:', result)
    return { changes: result.changes }
  } catch (error) {
    console.error('更新好友请求状态失败:', error)
    throw error
  }
}

/**
 * 根据接收者ID查询好友请求
 * @param toUserId 接收者用户ID
 * @param status 可选的状态过滤
 * @returns 好友请求数组
 */
function getFriendRequestsByToUserId(toUserId: string, status?: string) {
  try {
    if (!db) {
      throw new Error('数据库连接未建立')
    }

    let query = `
      SELECT * FROM friend_request 
      WHERE toUserId = @toUserId
    `
    const params: any = { toUserId }

    if (status) {
      query += ` AND status = @status`
      params.status = status
    }

    query += ` ORDER BY createTime DESC`

    const selectStmt = db.prepare(query)
    const requests = selectStmt.all(params)

    console.log('获取接收的好友请求成功，共', requests.length, '条')
    return requests
  } catch (error) {
    console.error('获取接收的好友请求失败:', error)
    throw error
  }
}

/**
 * 根据发送者ID查询好友请求
 * @param fromUserId 发送者用户ID
 * @param status 可选的状态过滤
 * @returns 好友请求数组
 */
function getFriendRequestsByFromUserId(fromUserId: string, status?: string) {
  try {
    if (!db) {
      throw new Error('数据库连接未建立')
    }

    let query = `
      SELECT * FROM friend_request 
      WHERE fromUserId = @fromUserId
    `
    const params: any = { fromUserId }

    if (status) {
      query += ` AND status = @status`
      params.status = status
    }

    query += ` ORDER BY createTime DESC`

    const selectStmt = db.prepare(query)
    const requests = selectStmt.all(params)

    console.log('获取发送的好友请求成功，共', requests.length, '条')
    return requests
  } catch (error) {
    console.error('获取发送的好友请求失败:', error)
    throw error
  }
}

/**
 * 获取指定会话的消息列表
 * @param conversationId 会话ID
 * @param limit 限制返回的消息数量
 * @returns 消息数组
 */
function getMessagesFromDatabase(conversationId: string, limit: number = 30) {
  try {
    if (!db) {
      throw new Error('数据库连接未建立')
    }

    const selectStmt = db.prepare(`
      SELECT * FROM messages 
      WHERE conversation_id = @conversationId 
      ORDER BY timestamp DESC 
      LIMIT @limit
    `)

    const messages = selectStmt.all({ conversationId, limit })

    // 反转顺序，让最早的消息在前面
    messages.reverse()

    console.log('获取会话消息成功，共', messages.length, '条')
    return messages
  } catch (error) {
    console.error('获取会话消息失败:', error)
    throw error
  }
}

/**
 * 关闭数据库连接
 */
function closeDatabase() {
  try {
    if (db) {
      db.close()
      console.log('数据库连接已关闭')
    }
  } catch (error) {
    console.error('关闭数据库连接失败:', error)
    throw error
  }
}

let isExitLogin: boolean = false

// 只在开发环境禁用安全警告
if (!app.isPackaged) {
  process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'
}

// 创建日志记录功能
// 日志文件目录
const logsDir = path.join(os.homedir(), '.chat', 'logs')
// 确保日志目录存在
if (!fs.existsSync(logsDir)) {
  fs.mkdirSync(logsDir, { recursive: true })
}

// 创建带有时间戳的日志文件名
const getLogFileName = () => {
  const now = new Date()
  const year = now.getFullYear()
  const month = String(now.getMonth() + 1).padStart(2, '0')
  const day = String(now.getDate()).padStart(2, '0')
  return `app-${year}${month}${day}.log`
}

const logFilePath = path.join(logsDir, getLogFileName())

// 日志记录函数
function logToFile(level: string, message: string) {
  const timestamp = new Date().toISOString()
  const logEntry = `[${timestamp}] [${level}] ${message}\n`

  try {
    fs.appendFileSync(logFilePath, logEntry)
  } catch (error) {
    console.error('Failed to write to log file:', error)
  }
}

// 注册IPC处理程序
function registerIpcHandlers() {
  // 数据库初始化
  ipcMain.handle('database-init-tables', async (event) => {
    try {
      console.log('接收到数据库初始化请求')
      if (!db) {
        initializeDatabase()
      } else {
        initTables()
      }
      return { success: true }
    } catch (error) {
      console.error('数据库初始化处理失败:', error)
      return { success: false, error: String(error) }
    }
  })

  // 添加消息
  ipcMain.handle('database-add-message', async (event, message) => {
    try {
      console.log('接收到添加消息请求:', message)
      return addMessageToDatabase(message)
    } catch (error) {
      console.error('添加消息处理失败:', error)
      return { success: false, error: String(error) }
    }
  })

  // 更新消息状态
  ipcMain.handle(
    'database-update-message-status',
    async (event, local_id, status) => {
      try {
        console.log('接收到更新消息状态请求:', { local_id, status })
        return updateMessageStatusInDatabase(local_id, status)
      } catch (error) {
        console.error('更新消息状态处理失败:', error)
        return { success: false, error: String(error) }
      }
    }
  )

  // 获取会话消息
  ipcMain.handle(
    'database-get-messages',
    async (event, conversationId, limit) => {
      try {
        console.log('接收到获取会话消息请求:', { conversationId, limit })
        return getMessagesFromDatabase(conversationId, limit)
      } catch (error) {
        console.error('获取会话消息处理失败:', error)
        return { success: false, error: String(error) }
      }
    }
  )

  // 添加好友申请
  ipcMain.handle(
    'database-add-friend-request',
    async (event, friendRequest) => {
      try {
        console.log('接收到添加好友申请请求:', friendRequest)
        return addFriendRequest(friendRequest)
      } catch (error) {
        console.error('添加好友申请处理失败:', error)
        return { success: false, error: String(error) }
      }
    }
  )

  // 更新好友申请状态
  ipcMain.handle(
    'database-update-friend-request-status',
    async (event, id, status) => {
      try {
        console.log('接收到更新好友申请状态请求:', { id, status })
        return updateFriendRequestStatus(id, status)
      } catch (error) {
        console.error('更新好友申请状态处理失败:', error)
        return { success: false, error: String(error) }
      }
    }
  )

  // 获取好友申请
  ipcMain.handle(
    'database-get-friend-requests-by-to-user-id',
    async (event, toUserId, status) => {
      try {
        console.log('接收到获取好友申请请求:', { toUserId })
        return getFriendRequestsByToUserId(toUserId, status)
      } catch (error) {
        console.error('获取好友申请处理失败:', error)
        return { success: false, error: String(error) }
      }
    }
  )

  // 刷新好友申请列表
  ipcMain.handle('friend-request-updated', async (event) => {
    try {
      console.log('接收到刷新好友申请列表请求')
      windows.main?.webContents.send('friend-request-refresh')
    } catch (error) {
      console.error('刷新好友申请列表处理失败:', error)
      return { success: false, error: String(error) }
    }
  })

  // 关闭数据库
  ipcMain.handle('database-close', async (event) => {
    try {
      console.log('接收到关闭数据库请求')
      closeDatabase()
      return { success: true }
    } catch (error) {
      console.error('关闭数据库处理失败:', error)
      return { success: false, error: String(error) }
    }
  })

  // 初始化WebSocket连接
  function initWebSocket(userId: string, url: string) {
    // 如果已经有连接，先断开
    if (ws) {
      ws.close()
    }
    currentUserId = userId
    wsUrl = url
    wsStatus = '连接中'
    try {
      console.log('主进程初始化WebSocket连接:', `${url}/chat?userId=${userId}`)
      ws = new WebSocket(`${url}/chat?userId=${userId}`)
      // 监听连接打开事件
      ws.addEventListener('open', () => {
        console.log('主进程WebSocket连接已建立')
        wsStatus = '已连接'
        wsAvailable = true
        // 重置重连计数器和标志
        reconnectAttempts = 0
        isManualClose = false
        // 处理队列中的消息
        processMessageQueue()
        // 通知所有窗口连接状态更新
        broadcastWsStatus()
        // 开启心跳检测
        startHeartbeat()
      })
      // 监听消息事件
      ws.addEventListener('message', (event: MessageEvent) => {
        const data = event.data as Buffer
        try {
          const message = JSON.parse(data.toString())
          console.log('主进程收到WebSocket消息:', dataFormat(message))
          // 广播消息给所有窗口
          broadcastWsMessage(message)
        } catch (error) {
          console.error('解析WebSocket消息失败:', dataFormat(error))
        }
      })
      // 监听连接关闭事件
      ws.addEventListener('close', () => {
        console.log('主进程WebSocket连接已关闭')
        wsStatus = '已断开'
        wsAvailable = false
        ws = null
        // 通知所有窗口连接状态更新
        broadcastWsStatus()
        // 非手动关闭且需要重连
        if (!isManualClose && reconnectAttempts < 5) {
          attemptReconnect()
        }
      })
      // 监听错误事件
      ws.addEventListener('error', (error) => {
        console.error('主进程WebSocket错误:', dataFormat(error))
        wsStatus = '连接错误'
        // 通知所有窗口连接状态更新
        broadcastWsStatus()
      })
    } catch (error) {
      console.error('主进程创建WebSocket连接失败:', error)
      wsStatus = '连接失败'
      // 通知所有窗口连接状态更新
      broadcastWsStatus()
    }
  }

  // 处理消息队列
  function processMessageQueue() {
    if (!ws || ws.readyState !== WebSocket.OPEN) return
    // 处理队列中的消息
    while (messageQueue.length > 0) {
      const message = messageQueue.shift()
      sendWsMessage(message)
    }
  }

  // 发送WebSocket消息
  function sendWsMessage(data: any): boolean {
    if (!ws || ws.readyState !== WebSocket.OPEN) {
      console.warn('WebSocket未连接，消息已加入队列')
      messageQueue.push(data)
      return false
    }
    try {
      // 添加时间戳到消息
      const messageWithTimestamp = {
        ...data,
        timestamp: new Date().toISOString().slice(0, 19) // 从ISO字符串中截取到秒级
      }
      ws.send(JSON.stringify(messageWithTimestamp))
      if (messageWithTimestamp.type !== 'heartbeat') {
        console.log(
          '主进程WebSocket消息发送成功:',
          dataFormat(messageWithTimestamp)
        )
      }
      return true
    } catch (error) {
      console.error('主进程发送WebSocket消息失败:', dataFormat(error))
      return false
    }
  }

  // 广播WebSocket状态给所有窗口
  function broadcastWsStatus() {
    Object.values(windows).forEach((window) => {
      if (window && !window.isDestroyed()) {
        window.webContents.send('ws-status-change', wsStatus)
      }
    })
  }

  // 广播WebSocket消息给所有窗口
  function broadcastWsMessage(message: any) {
    Object.values(windows).forEach((window) => {
      if (window && !window.isDestroyed()) {
        window.webContents.send('ws-message', message)
      }
    })
  }

  // 处理WebSocket发送消息请求
  ipcMain.handle(
    'ws-send',
    async (_event: Electron.IpcMainInvokeEvent, data: any) => {
      console.log('electron-main -> 主进程收到WebSocket发送请求:', data)
      const result = sendWsMessage(data)
      if (result) {
        return { success: true, message: '消息发送成功' }
      } else {
        return {
          success: false,
          error: ws ? 'WebSocket未连接' : 'WebSocket未初始化'
        }
      }
    }
  )

  // 处理获取WebSocket状态请求
  ipcMain.handle('ws-get-status', async () => {
    console.log('主进程收到获取WebSocket状态请求')
    console.log('当前WebSocket状态:', wsStatus)
    return wsStatus
  })

  // 处理初始化WebSocket连接请求
  ipcMain.handle(
    'ws-init',
    async (
      _event: Electron.IpcMainInvokeEvent,
      { userId, url }: { userId: string; url: string }
    ) => {
      console.log('主进程收到初始化WebSocket请求:', { userId, url })
      // 检查是否已经有相同用户的活跃连接
      if (ws && ws.readyState === WebSocket.OPEN && currentUserId === userId) {
        console.log('WebSocket已存在活跃连接，无需重复初始化')
        return { success: true, message: 'WebSocket已有活跃连接' }
      }
      // 避免短时间内重复初始化（防抖）
      const now = Date.now()
      if (now - lastInitTime < 1000) {
        // 1秒内不重复初始化
        console.log('短时间内已初始化WebSocket，忽略重复请求')
        return { success: true, message: '避免重复初始化' }
      }
      lastInitTime = now
      initWebSocket(userId, url)
      return { success: true, message: 'WebSocket初始化请求已处理' }
    }
  )

  // 处理WebSocket断开连接请求
  ipcMain.handle('ws-disconnect', async () => {
    console.log('主进程收到断开WebSocket连接请求')
    if (ws) {
      ws.close()
      ws = null
    }
    wsStatus = '已断开'
    wsAvailable = false
    broadcastWsStatus()
    stopHeartbeat()
    isManualClose = true
    return { success: true, message: 'WebSocket已断开' }
  })

  // 开启心跳检测
  function startHeartbeat() {
    stopHeartbeat()
    heartbeatTimer = Number(
      setInterval(() => {
        if (ws && ws.readyState === WebSocket.OPEN) {
          sendWsMessage({
            type: 'heartbeat',
            timestamp: new Date().toISOString().slice(0, 19)
          })
        }
      }, 5000)
    )
  }
  // 关闭心跳检测
  function stopHeartbeat() {
    if (heartbeatTimer) {
      clearInterval(heartbeatTimer)
      heartbeatTimer = null
    }
  }

  // 尝试重连
  function attemptReconnect() {
    reconnectAttempts++
    console.log(`主进程尝试第 ${reconnectAttempts} 次重连`)
    setTimeout(() => {
      if (!isManualClose) {
        if (currentUserId) {
          initWebSocket(currentUserId, wsUrl)
        }
      }
    }, defaultReconnectInterval)
  }
}

// 重写console方法，同时输出到控制台和日志文件
const originalConsoleLog = console.log
const originalConsoleInfo = console.info
const originalConsoleWarn = console.warn
const originalConsoleError = console.error
const originalConsoleDebug = console.debug

console.log = (...args: any[]) => {
  const message = args
    .map((arg) => (typeof arg === 'object' ? JSON.stringify(arg) : String(arg)))
    .join(' ')
  logToFile('LOG', message)
  originalConsoleLog(...args)
}

console.info = (...args: any[]) => {
  const message = args
    .map((arg) => (typeof arg === 'object' ? JSON.stringify(arg) : String(arg)))
    .join(' ')
  logToFile('INFO', message)
  originalConsoleInfo(...args)
}

console.warn = (...args: any[]) => {
  const message = args
    .map((arg) => (typeof arg === 'object' ? JSON.stringify(arg) : String(arg)))
    .join(' ')
  logToFile('WARN', message)
  originalConsoleWarn(...args)
}

console.error = (...args: any[]) => {
  const message = args
    .map((arg) => (typeof arg === 'object' ? JSON.stringify(arg) : String(arg)))
    .join(' ')
  logToFile('ERROR', message)
  originalConsoleError(...args)
}

console.debug = (...args: any[]) => {
  const message = args
    .map((arg) => (typeof arg === 'object' ? JSON.stringify(arg) : String(arg)))
    .join(' ')
  logToFile('DEBUG', message)
  originalConsoleDebug(...args)
}

console.log('=== 应用启动 ===')
console.log(`日志文件路径: ${logFilePath}`)

/**
 * 创建登录窗口函数
 * 负责初始化并配置登录窗口，设置窗口属性、预加载脚本和加载URL
 * @returns 创建的登录窗口实例
 */
function createLoginWindow(): BrowserWindow {
  // 如果已存在登录窗口，则聚焦
  if (windows.login && !windows.login.isDestroyed()) {
    windows.login.focus()
    return windows.login
  }
  // 创建登录窗口实例并配置窗口属性
  const loginWindow = new BrowserWindow({
    width: 310, // 窗口宽度
    height: 400, // 窗口高度
    show: false, // 初始不显示窗口，等待ready-to-show事件
    resizable: false, // 窗口不可调整大小
    icon: app.isPackaged
      ? path.join(process.resourcesPath, 'favicon.ico')
      : path.join(__dirname, 'public', 'favicon.ico'),
    webPreferences: {
      // 在生产环境中，预加载脚本会被包含在打包文件中
      preload: app.isPackaged
        ? path.join(process.resourcesPath, 'electron-preload.cjs')
        : path.join(__dirname, 'electron-preload.ts'),
      sandbox: false, // 禁用沙盒模式
      nodeIntegration: false, // 禁用节点集成，提高安全性
      contextIsolation: true, // 启用上下文隔离，提高安全性
      webSecurity: false // 禁用web安全策略，允许加载本地资源
    }
  })

  loginWindow.webContents.on('did-finish-load', () => {
    loginWindow.setTitle('即时通讯 - 登陆') // 强制设置
  })

  // 监听窗口准备就绪事件，当窗口内容加载完成后显示窗口
  loginWindow.on('ready-to-show', () => {
    loginWindow.show()
  })

  // 设置登录窗口的控制台日志捕获
  loginWindow.webContents.on(
    'console-message',
    (_event, level, message, sourceId, line) => {
      const windowName = '登录窗口'
      const logType =
        ['verbose', 'info', 'warning', 'error', 'debug'][level as number] ||
        'log'
      const sourceIdStr = String(sourceId)

      // 直接使用对应的console方法避免类型错误
      if (logType === 'log')
        console.log(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'info')
        console.info(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'warning')
        console.warn(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'error')
        console.error(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'debug')
        console.debug(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'verbose')
        console.log(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
    }
  )

  // 根据环境选择加载URL的方式
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    // 开发环境：加载开发服务器URL
    const devUrl = `${process.env['ELECTRON_RENDERER_URL'] || ''}/#/login`
    console.log('🌐 加载登录窗口:', devUrl)
    loginWindow.loadURL(devUrl)
    // 立即打开开发者工具，方便调试
    loginWindow.webContents.openDevTools()
  } else {
    // 生产环境：加载本地HTML文件
    // 在asar打包环境中，Electron会自动从app.asar中解析相对路径
    const htmlPath = app.isPackaged
      ? 'dist/index.html' // 相对于app.asar根目录的路径
      : path.join(__dirname, 'dist', 'index.html') // 开发环境下的路径

    console.log('📁 加载登录窗口HTML路径:', htmlPath)
    loginWindow.loadFile(htmlPath, {
      hash: 'login' // 设置URL哈希，用于前端路由
    })
  }
  // 监听窗口
  loginWindow.on('closed', () => {
    windows.login = undefined
  })
  windows.login = loginWindow

  // 返回创建的登录窗口实例
  return loginWindow
}

/**
 * 创建主窗口函数
 * 负责初始化并配置应用的主窗口，设置窗口属性、预加载脚本和加载URL
 * @returns 创建的主窗口实例
 */
function createMainWindow(): BrowserWindow {
  // 如果已存在主窗口，则聚焦
  if (windows.main && !windows.main.isDestroyed()) {
    windows.main.focus()
    return windows.main
  }
  // 创建主窗口实例并配置窗口属性
  const mainWindow = new BrowserWindow({
    width: 1000, // 窗口宽度
    height: 700, // 窗口高度
    minWidth: 800, // 窗口最小宽度
    minHeight: 500, // 窗口最小高度
    show: false, // 初始不显示窗口，等待ready-to-show事件
    icon: app.isPackaged
      ? path.join(process.resourcesPath, 'favicon.ico')
      : path.join(__dirname, 'public', 'favicon.ico'),
    // 在生产环境中，Electron会自动从resources目录加载资源
    webPreferences: {
      // 在生产环境中，预加载脚本会被包含在打包文件中
      preload: app.isPackaged
        ? path.join(process.resourcesPath, 'electron-preload.cjs')
        : path.join(__dirname, 'electron-preload.ts'),
      sandbox: false, // 禁用沙盒模式
      nodeIntegration: false, // 禁用节点集成，提高安全性
      contextIsolation: true, // 启用上下文隔离，提高安全性
      webSecurity: false // 禁用web安全策略，允许加载本地资源
      // enableRemoteModule已废弃，不再使用
    }
  })

  // 监听窗口准备就绪事件，当窗口内容加载完成后显示窗口
  mainWindow.on('ready-to-show', () => {
    mainWindow.show()
  })

  mainWindow.webContents.on('did-finish-load', () => {
    mainWindow.setTitle('即时通讯 - 欢迎使用') // 强制设置
  })

  // 设置主窗口的控制台日志捕获
  mainWindow.webContents.on(
    'console-message',
    (_event, level, message, sourceId, line) => {
      const windowName = '主窗口'
      const logType =
        ['verbose', 'info', 'warning', 'error', 'debug'][level as number] ||
        'log'
      const sourceIdStr = String(sourceId)

      // 直接使用对应的console方法避免类型错误
      if (logType === 'log')
        console.log(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'info')
        console.info(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'warning')
        console.warn(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'error')
        console.error(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'debug')
        console.debug(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'verbose')
        console.log(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
    }
  )

  // 根据环境选择加载URL的方式
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    // 开发环境：加载开发服务器URL
    const devUrl = `${process.env['ELECTRON_RENDERER_URL'] || ''}/#/main`
    console.log('🌐 加载主窗口:', devUrl)
    mainWindow.loadURL(devUrl)
    // 打开开发者工具，方便调试
    mainWindow.webContents.openDevTools()
  } else {
    // 生产环境：加载本地HTML文件
    const htmlPath = app.isPackaged
      ? 'dist/index.html' // 相对于app.asar根目录的路径
      : path.join(__dirname, 'dist', 'index.html') // 开发环境下的路径

    console.log('📁 加载主窗口HTML路径:', htmlPath)
    mainWindow.loadFile(htmlPath, {
      hash: 'main' // 设置URL哈希，用于前端路由
    })
  }
  // 监听窗口关闭事件
  mainWindow.on('closed', () => {
    windows.main = undefined
    // 主窗口关闭时，关闭所有其他窗口
    Object.values(windows).forEach((win) => {
      if (win && !win.isDestroyed()) {
        win.close()
      }
    })
  })
  windows.main = mainWindow
  // 启用remote模块
  remoteMain.enable(mainWindow.webContents)

  // 返回创建的主窗口实例
  return mainWindow
}

/**
 * 创建添加好友窗口函数
 * 负责初始化并配置添加好友窗口，设置窗口属性、预加载脚本和加载URL
 * @returns 创建的添加好友窗口实例
 */
function createdAddUserWindow(): BrowserWindow {
  // 如果已存在添加用户窗口，则聚焦
  if (windows.adduser && !windows.adduser.isDestroyed()) {
    windows.adduser.focus()
    return windows.adduser
  }
  // 创建添加好友窗口实例并配置窗口属性
  const addUserWindow = new BrowserWindow({
    width: 400,
    height: 460,
    parent: windows.main, // 设置父窗口为主窗口
    modal: false, // 非模态窗口，可以同时操作
    resizable: false, // 窗口不可调整大小
    show: false,
    icon: path.join(
      __dirname,
      app.isPackaged ? 'favicon.ico' : 'public/favicon.ico'
    ),
    // 在生产环境中，Electron会自动从resources目录加载资源
    webPreferences: {
      // 在生产环境中，预加载脚本会被包含在打包文件中
      preload: app.isPackaged
        ? path.join(process.resourcesPath, 'electron-preload.cjs')
        : path.join(__dirname, 'electron-preload.ts'),
      sandbox: false,
      nodeIntegration: false,
      contextIsolation: true,
      webSecurity: false
    }
  })

  // 根据环境加载URL
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    const devUrl = `${process.env['ELECTRON_RENDERER_URL'] || ''}/#/adduser`
    console.log('🌐 加载添加用户窗口:', devUrl)
    addUserWindow.loadURL(devUrl)
    addUserWindow.webContents.openDevTools()
  } else {
    // 生产环境：加载本地HTML文件
    const htmlPath = app.isPackaged
      ? 'dist/index.html' // 相对于app.asar根目录的路径
      : path.join(__dirname, 'dist', 'index.html') // 开发环境下的路径

    console.log('📁 加载添加用户窗口HTML路径:', htmlPath)
    addUserWindow.loadFile(htmlPath, {
      hash: 'adduser'
    })
  }
  // 设置主窗口的控制台日志捕获
  addUserWindow.webContents.on(
    'console-message',
    (_event, level, message, sourceId, line) => {
      const windowName = '子窗口 - 添加好友'
      const logType =
        ['verbose', 'info', 'warning', 'error', 'debug'][level as number] ||
        'log'
      const sourceIdStr = String(sourceId)

      // 直接使用对应的console方法避免类型错误
      if (logType === 'log')
        console.log(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'info')
        console.info(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'warning')
        console.warn(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'error')
        console.error(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'debug')
        console.debug(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'verbose')
        console.log(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
    }
  )
  addUserWindow.webContents.on('did-finish-load', () => {
    addUserWindow.setTitle('即时通讯 - 添加好友') // 强制设置
  })

  // 监听窗口准备就绪事件，当窗口内容加载完成后显示窗口
  addUserWindow.on('ready-to-show', () => {
    addUserWindow.show()
  })

  // 监听窗口关闭事件，将窗口引用设为null
  addUserWindow.on('closed', () => {
    windows.adduser = undefined
  })
  windows.adduser = addUserWindow
  return addUserWindow
}

/**
 * 创建添加好友窗口函数
 * 负责初始化并配置添加好友窗口，设置窗口属性、预加载脚本和加载URL
 * @returns 创建的添加好友窗口实例
 */
function createdFriendRequestWindow(): BrowserWindow {
  // 如果已存在好友申请窗口，则聚焦
  if (windows.friendrequest && !windows.friendrequest.isDestroyed()) {
    windows.friendrequest.focus()
    return windows.friendrequest
  }
  // 创建好友申请窗口实例并配置窗口属性
  const friendRequestWindow = new BrowserWindow({
    width: 600,
    height: 480,
    parent: windows.main, // 设置父窗口为主窗口
    modal: false, // 非模态窗口，可以同时操作
    resizable: false, // 窗口不可调整大小
    show: false,
    icon: path.join(
      __dirname,
      app.isPackaged ? 'favicon.ico' : 'public/favicon.ico'
    ),
    // 在生产环境中，Electron会自动从resources目录加载资源
    webPreferences: {
      // 在生产环境中，预加载脚本会被包含在打包文件中
      preload: app.isPackaged
        ? path.join(process.resourcesPath, 'electron-preload.cjs')
        : path.join(__dirname, 'electron-preload.ts'),
      sandbox: false,
      nodeIntegration: false,
      contextIsolation: true,
      webSecurity: false
    }
  })

  // 根据环境加载URL
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    const devUrl = `${
      process.env['ELECTRON_RENDERER_URL'] || ''
    }/#/friendrequest`
    console.log('🌐 加载好友申请窗口:', devUrl)
    friendRequestWindow.loadURL(devUrl)
    friendRequestWindow.webContents.openDevTools()
  } else {
    // 生产环境：加载本地HTML文件
    const htmlPath = app.isPackaged
      ? 'dist/index.html' // 相对于app.asar根目录的路径
      : path.join(__dirname, 'dist', 'index.html') // 开发环境下的路径

    console.log('📁 加载好友申请窗口HTML路径:', htmlPath)
    friendRequestWindow.loadFile(htmlPath, {
      hash: 'friendrequest'
    })
  }
  // 设置主窗口的控制台日志捕获
  friendRequestWindow.webContents.on(
    'console-message',
    (_event, level, message, sourceId, line) => {
      const windowName = '子窗口 - 好友申请'
      const logType =
        ['verbose', 'info', 'warning', 'error', 'debug'][level as number] ||
        'log'
      const sourceIdStr = String(sourceId)

      // 直接使用对应的console方法避免类型错误
      if (logType === 'log')
        console.log(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'info')
        console.info(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'warning')
        console.warn(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'error')
        console.error(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'debug')
        console.debug(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
      else if (logType === 'verbose')
        console.log(
          `[渲染进程:${windowName}] ${message} (${path.basename(
            sourceIdStr
          )}:${line})`
        )
    }
  )
  friendRequestWindow.webContents.on('did-finish-load', () => {
    friendRequestWindow.setTitle('即时通讯 - 好友申请') // 强制设置
  })

  // 监听窗口准备就绪事件，当窗口内容加载完成后显示窗口
  friendRequestWindow.on('ready-to-show', () => {
    friendRequestWindow.show()
  })

  // 监听窗口关闭事件，将窗口引用设为null
  friendRequestWindow.on('closed', () => {
    windows.friendrequest = undefined
  })
  windows.friendrequest = friendRequestWindow
  return friendRequestWindow
}

/**
 * 应用启动入口
 * 当Electron应用准备就绪时执行初始化逻辑
 */
app.whenReady().then(() => {
  // 设置应用用户模型ID，用于Windows任务栏标识
  electronApp.setAppUserModelId('com.chat')

  // 初始化数据库
  initializeDatabase()

  // 注册所有IPC处理程序
  registerIpcHandlers()

  // 监听新窗口创建事件，设置窗口属性
  app.on('browser-window-created', (_, window) => {
    if (process.platform === 'win32') {
      // 在Windows平台上隐藏菜单栏
      window.setAutoHideMenuBar(true)
      window.setMenuBarVisibility(false)
    }
  })

  // 简单的IPC通信测试
  ipcMain.on('ping', (_event: Electron.IpcMainEvent) => console.log('pong'))

  /**
   * 登录成功事件处理
   * 当用户登录成功后，关闭登录窗口并创建主窗口
   */
  ipcMain.on('login-success', (_event: Electron.IpcMainEvent) => {
    console.log('✅ 登录成功，关闭登录窗口并切换到主窗口')
    // 查找当前可见的登录窗口
    const loginWindow = BrowserWindow.getAllWindows().find((win) =>
      win.isVisible()
    )
    // 如果找到登录窗口，则关闭它
    if (loginWindow) {
      loginWindow.close()
    }
    // 创建并显示主窗口
    createMainWindow()
  })

  // 应用启动时创建登录窗口
  createLoginWindow()
  // createMainWindow()

  // 监听应用激活事件（macOS平台）
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      // 如果没有可见窗口，则创建主窗口
      createMainWindow()
    }
  })
})

/**
 * 监听所有窗口关闭事件
 * 在所有窗口关闭时决定是否退出应用
 */
app.on('window-all-closed', () => {
  // 在macOS平台上，应用通常在所有窗口关闭后仍保持运行
  if (process.platform !== 'darwin') {
    // 在非macOS平台上，当所有窗口关闭时退出应用，若仅仅是退出登录，则不退出应用
    if (isExitLogin) {
      isExitLogin = false
      createLoginWindow()
      return
    }
    app.quit()
  }
})

/**
 * 配置存储相关的IPC处理
 */
ipcMain.handle('store-set', (_event, key: string, value: any) => {
  try {
    // 使用类型断言来避免索引类型错误
    const storeObj = store as Record<string, any>
    if (value === undefined || value === null) {
      delete storeObj[key]
    } else {
      storeObj[key] = value
    }
    return true
  } catch (error) {
    console.error('Store set operation failed:', error)
    return false
  }
})

ipcMain.handle('store-get', (_event, key: string): any => {
  try {
    // 使用类型断言来避免索引类型错误
    const storeObj = store as Record<string, any>
    return storeObj[key]
  } catch (error) {
    console.error('Store get operation failed:', error)
    return undefined
  }
})

ipcMain.handle('store-delete', (_event, key: string) => {
  try {
    // 使用类型断言来避免索引类型错误
    const storeObj = store as Record<string, any>
    delete storeObj[key]
    return true
  } catch (error) {
    console.error('Store delete operation failed:', error)
    return false
  }
})

/**
 * 退出登录处理
 * 关闭主窗口并切换到登录窗口
 */
ipcMain.on('exit-login', (_event: Electron.IpcMainEvent) => {
  console.log('✅ 退出登录，关闭主窗口并切换到登录窗口')
  // 设置退出登录标志
  isExitLogin = true
  // 显式断开WebSocket连接，确保连接正确关闭
  console.log('显式断开WebSocket连接')
  if (ws) {
    ws.close()
    ws = null
  }
  wsStatus = '已断开'
  wsAvailable = false
  Object.values(windows).forEach((window) => {
    if (window && !window.isDestroyed()) {
      window.webContents.send('ws-status-change', wsStatus)
    }
  })
  if (heartbeatTimer) {
    clearInterval(heartbeatTimer)
    heartbeatTimer = null
  }
  isManualClose = true

  // 关闭主窗口
  if (windows.main && !windows.main.isDestroyed()) {
    windows.main.close()
    windows.main = undefined
  }
  // 创建并显示登录窗口
  createLoginWindow()
})

ipcMain.on('open-add-user-window', (_event: Electron.IpcMainEvent) => {
  console.log('✅ 打开添加好友窗口')
  // 创建并显示添加好友窗口
  createdAddUserWindow()
})

ipcMain.on('open-friend-request-window', (_event: Electron.IpcMainEvent) => {
  console.log('✅ 打开好友申请窗口')
  // 创建并显示好友申请窗口
  createdFriendRequestWindow()
})
